package com.zrc.japktool.apk.lib2cppTools;
import com.google.gson.Gson;
import com.zrc.japktool.apk.lib2cppTools.tools.*;
import com.zrc.japktool.util.TextUtils;
import org.json.JSONArray;
import org.json.JSONObject;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Main {
    static List<String> FuncNameList = new ArrayList();
    static List<String> TypeNameList = new ArrayList();
    static String ProjectPath;
    static String Il2cpp_Scaffolding_ARM64_Path = File.separator + "app" + File.separator + "src" + File.separator + "main" + File.separator + "cpp" + File.separator + "Il2cpp-Scaffolding-ARM64" + File.separator;

    public static void main(String[] args) {
        if (args.length > 0) {
            ProjectPath = args[0];
            doJob();
        } else {
            creatUI();
        }
    }

    private static void creatUI() {
        final JFrame frame = new JFrame("faker android 助理 by tianhou");
        frame.setSize(400, 300);
        frame.setDefaultCloseOperation(3);
        frame.setAlwaysOnTop(true);
        frame.setCursor(new Cursor(12));
        BorderLayout borderLayout = new BorderLayout();
        frame.setLayout(borderLayout);
        borderLayout.setVgap(50);
        final JLabel pathlabel = new JLabel("工作目录：");
        pathlabel.setSize(100, 100);
        pathlabel.setFont(new Font("SimSong", 1, 20));
        frame.add(pathlabel, "North");
        JButton button = new JButton("2 开始");
        button.setBounds(100, 50, 100, 40);
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Main.doJob();
            }
        });
        frame.add(button, "Center");
        JButton choosebutton = new JButton("1 选择工程目录");
        choosebutton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JFileChooser chooser = new JFileChooser();
                chooser.setFileSelectionMode(1);
                int option = chooser.showOpenDialog(frame);
                if (option == 0) {
                    File file = chooser.getSelectedFile();
                    System.out.println("选择的目录是：" + file.getAbsolutePath());
                    pathlabel.setText("工作目录：" + file.getAbsolutePath());
                    Main.ProjectPath = file.getAbsolutePath();
                } else {
                    System.out.println("取消");
                }

            }
        });
        frame.add(choosebutton, "West");
        frame.setVisible(true);
    }

    private static void doJob() {
        if (!TextUtils.isEmpty(ProjectPath)) {
            SettingHelper.getInstance().setProjectPath(ProjectPath);
            System.out.println("开始拷贝文件...");
            doCommonFile();
            System.out.println("分析Il2cpp函数...");
            doApiFunctionsPtr();
            System.out.println("分析游戏函数...");
            doFunctions();
            System.out.println("\n分析类型地址...");
            getNewTypesPtr();
            System.out.println("分析类型...");
            getNewTypes();
            System.out.println("任务完成！");
        }
    }

    private static void getNewTypes() {
        String path = SettingHelper.getInstance().getProjectPath() + Il2cpp_Scaffolding_ARM64_Path;
        String name = DumperHelper.getInstance().getil2cppHFile();

        try {
            FileHelper.EraserBadChar(name);
            FileHelper.copyFile(new File(name), new File(path + "il2cpp.h"));
        } catch (IOException var3) {
            throw new RuntimeException(var3);
        }

        StringBuilder text = (new StringBuilder()).append("\r\n");
    }

    private static void doCommonFile() {
        String ArmPath = SettingHelper.getInstance().getProjectPath() + Il2cpp_Scaffolding_ARM64_Path;
        String CppPath = ArmPath.substring(0, ArmPath.length() - 25);
        String CommonFilePath = "." + File.separator + "common" + File.separator;
        try {
            FileHelper.mkdirs(ArmPath);
            String name = "il2cpp-api-functions.h";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "il2cpp-appdata.h";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "il2cpp-init.cpp";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "il2cpp-init.h";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "il2cpp-metadata-version.h";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "il2cpp-types.h";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "MonoString.cpp";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "MonoString.h";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(ArmPath + name));
            name = "native-lib.cpp";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(CppPath + name));
            name = "CMakeLists.txt";
            FileHelper.copyFile(new File(CommonFilePath + name), new File(CppPath + name));
        } catch (IOException var4) {
            throw new RuntimeException(var4);
        }
    }

    private static void doApiFunctionsPtr() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(SymbleFileHelper.getInstance().getName()), "UTF-8"));
            Throwable var1 = null;
            try {
                String line;
                try {
                    while((line = br.readLine()) != null) {
                        if (line.indexOf("il2cpp_") > 0) {
                            String ptr = line.substring(8, 16);
                            String name = line.substring(line.indexOf("il2cpp_"));
                            String temp = "#define " + name + "_ptr 0x" + ptr + "\n";
                            String filePath = SettingHelper.getInstance().getProjectPath() + Il2cpp_Scaffolding_ARM64_Path + "il2cpp-api-functions-ptr.h";
                            FileHelper.AppendTextToFile(filePath, temp);
                        }
                    }
                } catch (Throwable var15) {
                    var1 = var15;
                    throw var15;
                }
            } finally {
                if (br != null) {
                    if (var1 != null) {
                        try {
                            br.close();
                        } catch (Throwable var14) {
                            var1.addSuppressed(var14);
                        }
                    } else {
                        br.close();
                    }
                }

            }
        } catch (IOException var17) {
            System.err.println("Error reading file: " + var17.getMessage());
        }

    }

    private static void doFunctions() {
        String head = "using namespace app;\n";
        String path = SettingHelper.getInstance().getProjectPath() + Il2cpp_Scaffolding_ARM64_Path;
        String filename = path + "il2cpp-functions.h";
        FileHelper.AppendTextToFile(filename, head);
        String dumpScriptFile = DumperHelper.getInstance().getScriptFile();
        JSONArray jsonArray = getScriptJsonArray(dumpScriptFile, "ScriptMethod");
        int size = jsonArray.length();
        Set<String> functionNames = new HashSet();

        for(int i = 0; i < size; ++i) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            int address = jsonObject.getInt("Address");
            String signature = jsonObject.getString("Signature");
            signature = replaceKeywords(signature);
            signature = numberParameters(signature);
            signature = handleNameDuplicates(signature, functionNames, address);
            String line = formatSignature(address, signature);
            FileHelper.AppendTextToFile(filename, line);
            if (i % (size / 10) == 0) {
                System.out.print("...");
            }
        }

    }

    private static String numberParameters(String signature) {
        String[] parts = signature.split(", ");
        Map<String, Integer> nameCounts = new HashMap();
        StringBuilder numberedSignature = new StringBuilder();

        for(int i = 0; i < parts.length; ++i) {
            String part = parts[i].trim();
            int lastSpaceIndex = part.lastIndexOf(" ");
            if (lastSpaceIndex > -1) {
                String name = part.substring(lastSpaceIndex + 1);
                if (nameCounts.containsKey(name)) {
                    int count = (Integer)nameCounts.get(name) + 1;
                    nameCounts.put(name, count);
                    parts[i] = part.substring(0, lastSpaceIndex + 1) + name + count;
                } else {
                    nameCounts.put(name, 0);
                }
            }

            numberedSignature.append(parts[i]);
            if (i < parts.length - 1) {
                numberedSignature.append(", ");
            }
        }

        return numberedSignature.toString();
    }

    private static String replaceKeywords(String signature) {
        String[] keywords = new String[]{"method,", "or,", "not,", "operator,", "this,", "static,", "catch,", "delete,", "export,"};
        String[] var2 = keywords;
        int var3 = keywords.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String keyword = var2[var4];
            signature = signature.replace(keyword, keyword.split(",")[0] + "0,");
        }

        return signature;
    }

    private static String handleNameDuplicates(String signature, Set<String> functionNames, int address) {
        int x = signature.indexOf(" ");
        int y = signature.indexOf(" ", signature.indexOf(" ") + 1);
        String name = signature.substring(x + 1, y);
        if (functionNames.contains(name)) {
            signature = signature.replaceFirst(name, name + "_" + address);
        } else {
            functionNames.add(name);
        }

        return signature;
    }

    private static String formatSignature(int address, String signature) {
        signature = signature.replaceFirst(" ", ", ").replaceFirst(" \\(", ", (").replaceFirst("\\);", "));\r\n");
        return "DO_APP_FUNC(0x" + Integer.toHexString(address).toUpperCase() + ", " + signature;
    }

    private static String doLine(String line) {
        String ret = line;

        for(int i = 0; ret.indexOf(" __,") > 0; ++i) {
            ret = ret.replaceFirst(" __,", " __" + i + ",");
        }

        return ret;
    }

    private static boolean HasSameName(List<String> list, String name) {
        boolean ret = false;

        for(int i = 0; i < list.size(); ++i) {
            if (((String)list.get(i)).equals(name)) {
                ret = true;
                break;
            }
        }

        if (!ret) {
            list.add(name);
        }

        return ret;
    }

    private static JSONObject getScriptJson(String ScriptFileName) {
        long length = FileHelper.getLength(ScriptFileName);
        if (length > 134217728L) {
            System.out.println("buffer is not enough");
            return null;
        } else {
            String data = null;

            try {
                data = FileHelper.readLargeFile(ScriptFileName);
            } catch (Exception var6) {
                throw new RuntimeException(var6);
            }

            data = data.replace("\r\n", "");
            JSONObject jsonObject = new JSONObject(data);
            return jsonObject;
        }
    }

    private static JSONArray getScriptJsonArray(String ScriptFileName, String name) {
        JSONObject jsonObject = getScriptJson(ScriptFileName);
        JSONArray jsonArray = jsonObject.getJSONArray(name);
        return jsonArray;
    }

    private static void getNewTypesPtr() {
        JSONArray jsonArray = getScriptJsonArray(DumperHelper.getInstance().getScriptFile(), "ScriptMetadata");
        StringBuilder il2cpp_types_ptr_Text = (new StringBuilder()).append("\r\n");
        for(int j = 0; j < jsonArray.length(); ++j) {
            JSONObject obj = jsonArray.getJSONObject(j);
            String Signature = "";

            try {
                Signature = obj.getString("Signature");
            } catch (Exception var9) {
            }
            if (!TextUtils.isEmpty(Signature) && Signature.endsWith("_c*")) {
                Signature = Signature.substring(0, Signature.length() - 3);
                if (!HasSameName(TypeNameList, Signature)) {
                    int Address = obj.getInt("Address");
                    String line = "DO_TYPEDEF(0x" + Integer.toHexString(Address).toUpperCase() + ", " + Signature + ");\r\n";
                    il2cpp_types_ptr_Text.append(line);
                }
            }
        }

        try {
            String path = SettingHelper.getInstance().getProjectPath() + Il2cpp_Scaffolding_ARM64_Path + "il2cpp-types-ptr.h";
            FileHelper.write(path, il2cpp_types_ptr_Text.toString());
        } catch (Exception var8) {
            throw new RuntimeException(var8);
        }
    }
}
